#include "muduo/net/TcpServer.h"

#include "muduo/base/AsyncLogging.h"
#include "muduo/base/Logging.h"
#include "muduo/base/Thread.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/InetAddress.h"

#include <functional>
#include <utility>

#include <stdio.h>
#include <unistd.h>
#include <iostream>

using namespace muduo;
using namespace muduo::net;

class EchoServer {
public:
    EchoServer(EventLoop *loop, const InetAddress &listenAddr)
            : loop_(loop),
              server_(loop, listenAddr, "EchoServer") {
        server_.setConnectionCallback(
                std::bind(&EchoServer::onConnection, this, _1));
        server_.setMessageCallback(
                std::bind(&EchoServer::onMessage, this, _1, _2, _3));
    }

    void start() {
        server_.start();
    }


    void onConnection(const TcpConnectionPtr &conn);

    void onMessage(const TcpConnectionPtr &conn, Buffer *buf, Timestamp time);

    void send(const TcpConnectionPtr &conn, const std::string msg);

    EventLoop *loop_;
    TcpServer server_;

};

void EchoServer::onConnection(const TcpConnectionPtr &conn) {
    LOG_INFO << conn->peerAddress().toIpPort() << " -> "
              << conn->localAddress().toIpPort() << " is "
              << (conn->connected() ? "UP" : "DOWN");
}

void EchoServer::onMessage(const TcpConnectionPtr &conn, Buffer *buf, Timestamp time) {
    string msg(buf->retrieveAllAsString());
    LOG_INFO << conn->name() << " recv " << msg.size() << " bytes at " << time.toString();
    this->send(conn, msg);
}

void EchoServer::send(const TcpConnectionPtr &conn, const std::string msg) {
    conn->send(msg);
}

int main(int argc, char *argv[]) {

    LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid();
    EventLoop loop;
    InetAddress listenAddr(2007);
    EchoServer server(&loop, listenAddr);

    server.start();

    loop.loop();
}

